﻿using System;
using System.Diagnostics;
using System.IO;

namespace Algorithm_Comparison
{
    class Program
    {
        // Experiment results are written to the file line per line,
        // meaning you can close the process before finishing the entire experiment
        static void Main()
        {
            Console.WriteLine("Press 1 to run experiment 1");
            Console.WriteLine("Press 2 to run experiment 2");
            int input = Convert.ToInt32(Console.ReadLine());
            if (input == 1)
            {
                /*
                 * Experiment 1
                 * p=20
                 * t=2
                 * 
                 * Run ILS(Mm) and note number of exchanges
                 * Then run the other 3 algorithms with roughly the same number of exchanges
                 * 
                 * Problem sizes:
                 * NumberOfPoints: 10, 30, 50 (100 is way too slow)
                 * Dimension: 3, 7
                 * 
                 * Data is saved in text file named Experiment1-<numberOfPoints>x<dimension>.txt
                 */

                for (int repeat = 0; repeat < 20; repeat++)
                    foreach (int numberOfPoints in new[] {10, 20, 50})
                    {
                        foreach (int dimension in new[] {3, 7})
                        {
                            Console.WriteLine("===================================================");
                            Console.WriteLine("===================================================");
                            Console.WriteLine("Starting LHD: " + numberOfPoints + "x" + dimension);
                            int currentNumberOfResults = 0;

                            String fileName = "Experiment1-" + numberOfPoints + "x" + dimension + ".txt";

                            if (!File.Exists(fileName)) // Write column names on first line if file doesn't exist yet
                            {
                                String firstLine =
                                    String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}" + Environment.NewLine,
                                        "Exchanges",
                                        "ILS(Mm) MM",
                                        "ILS(Mm) ms",
                                        "ILS(PhiP) MM",
                                        "ILS(PhiP) ms",
                                        "ESE(Mm) MM",
                                        "ESE(Mm) ms",
                                        "ESE(PhiP) MM",
                                        "ESE(PhiP) ms"
                                        ); 
                                File.AppendAllText(fileName, firstLine);
                            }

                            while (currentNumberOfResults < 5)
                            {
                                // Iterated Local Search (Maximin)
                                var stopWatchILSMM = new Stopwatch();

                                stopWatchILSMM.Start();
                                LHD initialLHD = new LHD(numberOfPoints, dimension);
                                initialLHD.SetRandomMatrixILS();
                                initialLHD.CalculateDistanceMatrix();
                                initialLHD.CalculatePointMinDistance();
                                var ilsMM = new IteratedLocalSearchMaximin(initialLHD);

                                stopWatchILSMM.Stop();

                                Console.Write("ILS MM: " + stopWatchILSMM.ElapsedMilliseconds);

                                // Iterated Local Search (PhiP)
                                var stopWatchILSPhiP = new Stopwatch();

                                stopWatchILSPhiP.Start();
                                initialLHD = new LHD(numberOfPoints, dimension);
                                initialLHD.SetRandomMatrixILS();
                                initialLHD.CalculateDistanceMatrix();
                                initialLHD.CalculatePointMinDistance();
                                var ilsPhiP = new IteratedLocalSearchPhiP(initialLHD, 20,
                                    ilsMM.NrOfExchanges);

                                stopWatchILSPhiP.Stop();

                                Console.Write(" || ILS PhiP: " + stopWatchILSPhiP.ElapsedMilliseconds);

                                // Enhanced Stochastic Evolutionary (Maximin)
                                var stopWatchESEMM = new Stopwatch();

                                stopWatchESEMM.Start();
                                initialLHD = new LHD(numberOfPoints, dimension);
                                initialLHD.SetRandomMatrixESE();
                                var eseMM = new EnhancedStochasticEvolutionaryMaximin(initialLHD, -1, ilsMM.NrOfExchanges, true);

                                eseMM.BestRecordedMaximinLHD.ConvertPointsFromEseToIls();
                                eseMM.BestRecordedMaximinLHD.CalculateDistanceMatrix();
                                eseMM.BestRecordedMaximinLHD.CalculatePointMinDistance();

                                stopWatchESEMM.Stop();

                                Console.Write(" || ESE MM: " + stopWatchESEMM.ElapsedMilliseconds);

                                // Enhanced Stochastic Evolutionary (PhiP)
                                var stopWatchESEPhiP = new Stopwatch();

                                stopWatchESEPhiP.Start();
                                initialLHD = new LHD(numberOfPoints, dimension);
                                initialLHD.SetRandomMatrixESE();
                                var esePhiP = new EnhancedStochasticEvolutionaryPhiP(initialLHD, 20, -1, ilsMM.NrOfExchanges, true);

                                esePhiP.BestRecordedMaximinLHD.ConvertPointsFromEseToIls();
                                esePhiP.BestRecordedMaximinLHD.CalculateDistanceMatrix();
                                esePhiP.BestRecordedMaximinLHD.CalculatePointMinDistance();

                                stopWatchESEPhiP.Stop();

                                // Write data to file
                                Console.Write(" || ESE PhiP: " + stopWatchESEPhiP.ElapsedMilliseconds);
                                String text =
                                    String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}" + Environment.NewLine,
                                        ilsMM.NrOfExchanges,
                                        Math.Pow(ilsMM.BestRecordedMaximinLHD.MinDistance, 2),
                                        stopWatchILSMM.ElapsedMilliseconds,
                                        Math.Pow(ilsPhiP.BestRecordedMaximinLHD.MinDistance, 2),
                                        stopWatchILSPhiP.ElapsedMilliseconds,
                                        Math.Pow(eseMM.BestRecordedMaximinLHD.MinDistance, 2),
                                        stopWatchESEMM.ElapsedMilliseconds,
                                        Math.Pow(esePhiP.BestRecordedMaximinLHD.MinDistance, 2),
                                        stopWatchESEPhiP.ElapsedMilliseconds
                                        );
                                File.AppendAllText(fileName, text);

                                Console.WriteLine(" || done with " + currentNumberOfResults);
                                currentNumberOfResults++;
                            }
                        }
                    }
            }
            else
            {
                /*
                 * Experiment 2: goal is to compare the PhiP value of the resulting LHD of LHD(PhiP) and ESE(PhiP)
                 * p = 20, 50, 30
                 * t=1 (distance = non euclidian)
                 * 
                 * Run ILS(PhiP) and note number of exchanges
                 * Then run Ese(PhiP) with same number of exchanges
                 * 
                 * Problem sizes:
                 * NumberOfPoints: 10, 20, 50 (100 is way too slow)
                 * Dimension: 3, 7
                 * 
                 * Data is saved in text file named Experiment2-p=<pValue> <numberOfPoints>x<dimension>.txt
                 */
                for (int repeat = 0; repeat < 20; repeat++)
                    foreach (int pValue in new [] { 20, 50, 30 })
                    foreach (int numberOfPoints in new [] {10, 20, 50})
                    {
                        foreach (int dimension in new [] {3, 7})
                        {
                            Console.WriteLine("===================================================");
                            Console.WriteLine("===================================================");
                            Console.WriteLine("Starting LHD: p=" + pValue + " " + numberOfPoints + "x" + dimension);
                            int currentNumberOfResults = 0;

                            String fileName = "Experiment2-p=" + pValue + "-" + numberOfPoints + "x" + dimension + ".txt";
                            if (!File.Exists(fileName))
                            {
                                String firstLine = String.Format("{0}\t{1}\t{2}\t{3}\t{4}" + Environment.NewLine,
                                        "Exchanges",
                                        "ILS(PhiP) PhiP",
                                        "ILS(PhiP) ms",
                                        "ESE(PhiP) PhiP",
                                        "ESE(PhiP) ms"
                                        );
                                    
                                File.AppendAllText(fileName, firstLine);
                            }
                            while (currentNumberOfResults < 5)
                            {
                                LHD initialLHD = new LHD(numberOfPoints, dimension);

                                // Iterated Local Search (PhiP)
                                var stopWatchILSPhiP = new Stopwatch();

                                stopWatchILSPhiP.Start();
                                initialLHD = new LHD(numberOfPoints, dimension);
                                initialLHD.SetRandomMatrixILS();
                                initialLHD.CalculateDistanceMatrix(false);
                                initialLHD.CalculatePointMinDistance();
                                var ilsPhiP = new IteratedLocalSearchPhiP(initialLHD, pValue, long.MaxValue, false);
                                ilsPhiP.EndResult.ConvertPointsFromILSToEse();
                                ilsPhiP.EndResult.CalculateDistanceMatrix(false);
                                ilsPhiP.EndResult.CalculatePointMinDistance();
                                ilsPhiP.EndResult.CalculatePhiP(pValue);

                                stopWatchILSPhiP.Stop();

                                Console.Write("ILS PhiP: " + stopWatchILSPhiP.ElapsedMilliseconds);

                                // Enhanced Stochastic Evolutionary (PhiP)
                                var stopWatchESEPhiP = new Stopwatch();

                                stopWatchESEPhiP.Start();
                                initialLHD = new LHD(numberOfPoints, dimension);
                                initialLHD.SetRandomMatrixESE();
                                var esePhiP = new EnhancedStochasticEvolutionaryPhiP(initialLHD, pValue, -1, ilsPhiP.NrOfExchanges, false);


                                stopWatchESEPhiP.Stop();

                                Console.Write(" || ESE PhiP: " + stopWatchESEPhiP.ElapsedMilliseconds);
                                String text =
                                    String.Format("{0}\t{1}\t{2}\t{3}\t{4}" + Environment.NewLine,
                                        ilsPhiP.NrOfExchanges,
                                        ilsPhiP.EndResult.LastCalculatedPhiP,
                                        stopWatchILSPhiP.ElapsedMilliseconds,
                                        esePhiP.EndResult.LastCalculatedPhiP,
                                        stopWatchESEPhiP.ElapsedMilliseconds
                                        );
                                File.AppendAllText(fileName, text);

                                Console.WriteLine(" || done with " + currentNumberOfResults);
                                currentNumberOfResults++;
                            }
                        }
                    }
            }
            Console.WriteLine("Done");
            Console.ReadLine();
        }
    }
}
